#include <iostream>
#include <deque>
#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/bind.hpp>

void do_decode(const data_packet& packet);

class work_queue {
public:
	typedef boost::function<void()> task_type;

private:
	std::deque<task_type> tasks_;
	boost::mutex tasks_mutex_;
	boost::condition_variable cond_;

public:
	void push_task(const task_type& task) {
		boost::unique_lock<boost::mutex> lock(tasks_mutex_);
		tasks_.push_back(task);
		lock.unlock();
		cond_.notify_one();
	}

	task_type try_pop_task() {
		task_type ret;
		boost::lock_guard<boost::mutex> lock(tasks_mutex_);
		if (!tasks_.empty()) {
			ret = tasks_.front();
			tasks_.pop_front();
		}
		return ret;
	}

	task_type pop_task() {
		boost::unique_lock<boost::mutex> lock(tasks_mutex_);
		while (tasks_.empty()) {
			cond_.wait(lock);
		}
		task_type ret = tasks_.front();
		tasks_.pop_front();
		return ret;
	}

	std::size_t size()
	{
		return tasks_.size();
	}
};

work_queue g_queue;

void do_nothing()
{
	std::cout << "do_nothing" << std::endl;
}

const std::size_t tests_tasks_count = 3000;

void pusher(){
	for (std::size_t i = 0; i < tests_tasks_count; ++i)
	{
		g_queue.push_task(&do_nothing);
	}
}

void proper_sync() {
	for (std::size_t i = 0; i < tests_tasks_count; ++i) {
		g_queue.pop_task()();
	}
}

int main()
{
	boost::thread pop_sync1(&proper_sync);
	boost::thread pop_sync2(&proper_sync);
	boost::thread pop_sync3(&proper_sync);

	boost::thread push1(&pusher);
	boost::thread push2(&pusher);
	boost::thread push3(&pusher);

	pop_sync1.join();
	pop_sync2.join();
	pop_sync3.join();

	push1.join();
	push2.join();
	push3.join();

	std::cout << "g_queue.size():" << g_queue.size() << std::endl;

	return 0;
}